package com.yan.ems.service;

import com.mathworks.engine.MatlabEngine;
import com.opencsv.CSVReader;
import com.opencsv.CSVReaderBuilder;
import com.yan.ems.exception.ForecastException;
import com.yan.ems.pojo.param.TimeRangeParam;
import com.yan.ems.pojo.vo.EnergyForecastResponse;
import com.yan.ems.pojo.vo.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.*;

@Slf4j
@Service
public class ForecastService {
	public Result<EnergyForecastResponse> forecast(MultipartFile csvFile, TimeRangeParam timeRange) {
		try {
			log.info("------start saveCsv--------------");
			saveCsvFile(csvFile);	// 保存到 py/data/${csvFile.originalName} 下
			log.info("------succeed saveCsv------------");
			log.info("------start run python-----------");
			runPython(csvFile, timeRange);		// 执行python脚本，生成stl分解结果，保存到 matlab/forecast/data_decomposednew.csv 下
			log.info("------succeed run python---------");
			log.info("------start run matlab-----------");
			runMatlab();			// 执行matlab脚本，生成预测结果，保存到 matlab/forecast/result/testdata.csv 下
			log.info("------succeed run matlab---------");

			List<Double> originData = new ArrayList<>();
			List<Double> predictData = new ArrayList<>();
			List<Double> seasonalData = new ArrayList<>();
			List<Double> trendData = new ArrayList<>();
			List<Double> residualData = new ArrayList<>();
			List<String> timestamps = new ArrayList<>();

			String result = "matlab/forecast/result/testdata.csv";

			log.info("start reading file");
			try (FileReader fileReader = new FileReader(result);
				CSVReader csvReader = new CSVReaderBuilder(fileReader).build();) {
				String[] nextRecord;
				nextRecord = csvReader.readNext();
				while ((nextRecord = csvReader.readNext()) != null) {
					timestamps.add(nextRecord[0]);
					seasonalData.add(Double.parseDouble(nextRecord[1]));
					trendData.add(Double.parseDouble(nextRecord[2]));
					residualData.add(Double.parseDouble(nextRecord[3]));
					originData.add(Double.parseDouble(nextRecord[4]));
					predictData.add(Double.parseDouble(nextRecord[5]));
				}
			} catch (Exception e) {
				throw new RuntimeException("文件读不好");

			}
			log.info("succeed reading file");

			return Result.success(new EnergyForecastResponse(timestamps, originData, predictData, seasonalData, trendData, residualData));
		} catch (Exception e) {
			throw new ForecastException();
		}
	}

	private void runMatlab() throws Exception {
		String command = "run('matlab/forecast/main.m')";
		MatlabEngine engine = MatlabEngine.startMatlab();
		System.out.println("matlab start succeed");
		engine.eval(command);
		engine.eval("disp('Script execution completed.')");
		engine.close();
		System.out.println("matlab succeed");
	}

	private void saveCsvFile(MultipartFile csvFile) throws Exception {
		String fileName = csvFile.getOriginalFilename();
		String path = System.getProperty("user.dir") + File.separator + "py" + File.separator + "data" + File.separator;
		File file = new File(path);
		if (!file.exists()) {
			file.mkdirs();
		}
		path = file.getPath() + File.separator + fileName;
		try {
			csvFile.transferTo(new File(path));
		} catch (Exception e) {
			System.out.println(e.getMessage());
			throw new ForecastException();
		}
	}

	private void runPython(MultipartFile csvFile, TimeRangeParam timeRange) throws Exception {
		Process exec = getProcess(csvFile, timeRange);
		pythonOutput(exec);

		System.out.println("python start success!");
		exec.waitFor();
		exec.destroy();

		System.out.println("python run success!");
	}

	private void pythonOutput(Process exec) throws IOException {
		BufferedReader stdInput = new BufferedReader(new InputStreamReader(exec.getInputStream()));
		String s;
		while ((s = stdInput.readLine()) != null) {
			System.out.println(s);
		}

		BufferedReader stdError = new BufferedReader(new InputStreamReader(exec.getErrorStream()));
		while ((s = stdError.readLine()) != null) {
			System.err.println(s);
		}
		stdInput.close();
		stdError.close();
	}

	private static Process getProcess(MultipartFile csvFile, TimeRangeParam timeRange) throws IOException {
		Runtime runtime = Runtime.getRuntime();
		String pythonPath = "py" + File.separator + "savestlresult.py";
		String dataPath = "py" + File.separator + "data" + File.separator;
		String fileName = csvFile.getOriginalFilename();
		String pyenv = "py" + File.separator + "env" + File.separator + "pyenv" + File.separator + "Scripts" + File.separator + "activate && ";
		String command = "cmd /c " + pyenv + "python " + pythonPath + " " + dataPath + fileName + String.format(" %d %d", timeRange.getStartHour(), timeRange.getEndHour());
		return runtime.exec(command);
	}
}
